﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.Geometries
{
    /// <summary>
    /// 椭圆
    /// </summary>
    /// <remarks>
    /// 𝑥^2/𝑎^2 +𝑦^2/𝑏^2 =1 a为x方向半径b为y方向半径
    /// </remarks>
    public class Ellipse
    {
        public Ellipse(Vector2 center, float width, float height)
        {
            if (width <= 0f || height <= 0f)
            {
                throw new ArgumentOutOfRangeException("arguments out of range.the 'width' and 'height' must greater than zero.");
            }
            this.Center = center;
            this.Width = width;
            this.Height = height;
        }
        public Ellipse(float x, float y, float width, float height)
        {
            if (width <= 0f || height <= 0f)
            {
                throw new ArgumentOutOfRangeException("arguments out of range.the 'width' and 'height' must greater than zero.");
            }
            this.Width = width;
            this.Height = height;
            this.Center = new Vector2(x + width / 2, y + height / 2);

        }
        /// <summary>
        /// 宽度
        /// </summary>
        public float Width { get; set; }
        /// <summary>
        /// 高度
        /// </summary>
        public float Height { get; set; }

        /// <summary>
        /// 中心坐标
        /// </summary>
        public Vector2 Center { get; set; }

        /// <summary>
        /// 获取指定偏移角度处的点坐标
        /// </summary>
        /// <param name="angle">角度</param>
        /// <returns></returns>
        public Vector2 GetPointByAngle(float angle)
        {
            var a = this.Width / 2;
            var b = this.Height / 2;

            angle %= 360f;//规范角度

            var radian = MathF.PI * angle / 180f;
            var x = (a * b) / MathF.Sqrt((MathF.Pow(b, 2) + MathF.Pow(a * MathF.Tan(radian), 2)));
            var y = (a * b) / MathF.Sqrt((MathF.Pow(a, 2) + MathF.Pow(b / MathF.Tan(radian), 2)));
            if (angle > 90 && angle < 270)
            {
                x = -x;
            }
            if (angle > 180 && angle < 360)
            {
                y = -y;
            }
            return new Vector2(x, y);
        }


        /// <summary>
        /// 椭圆是否包含指定的点。（点是否在椭圆内【包括椭圆边界】）
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public bool Contains(Vector2 p)
        {
            var a = this.Width / 2;
            var b = this.Height / 2;
            var center = this.Center;
            return (MathF.Pow(p.X - center.X, 2) / MathF.Pow(a, 2)) + (MathF.Pow(p.Y - center.Y, 2) / MathF.Pow(b, 2)) <= 1;
        }
        /// <summary>
        /// 点是否正在椭圆圆周上（即坐标满足椭圆公式）
        /// </summary>
        /// <param name="p"></param>
        /// <param name="tolerance">允许的误差</param>
        /// <returns></returns>
        public bool IsEdge(Vector2 p, float tolerance = 0.01f)
        {
            var a = this.Width / 2;
            var b = this.Height / 2;
            var center = this.Center;
            var r = (MathF.Pow(p.X - center.X, 2) / MathF.Pow(a, 2)) + (MathF.Pow(p.Y - center.Y, 2) / MathF.Pow(b, 2));
            return r < 1 + tolerance && r > 1 - tolerance;
        }
        /// <summary>
        /// 获取椭圆的周长（近似值）
        /// </summary>
        /// <returns></returns>
        /// <remarks>使用印度数学家拉马努金发现的公式</remarks>
        public float GetPerimeter()
        {
            var a = this.Width / 2;
            var b = this.Height / 2;
            var h = MathF.Pow(a - b, 2) / MathF.Pow(a + b, 2);
            return MathF.PI * (a + b) * (1 + 3 * h / (10 + MathF.Sqrt(4 - 3 * h)));

        }
        /// <summary>
        /// 获取椭圆的面积
        /// </summary>
        /// <returns></returns>
        public float GetArea()
        {
            var a = this.Width / 2;
            var b = this.Height / 2;
            return MathF.PI * a * b;
        }
    }
}
